package dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import externaldata.theoricaltimefile.TheoricalTrainData;
import pari.Pari;
import pari.PariHistorique;
import user.Friendship;
import user.User;

public class DaoUser extends DAO<User> {

	@Override
	public List<User> find(String id) {
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		List<User> rep = null;
		try{
			tr = session.beginTransaction();
			criteria.add(Restrictions.eq("mail", id));
			rep = criteria.list();
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return rep;
	}

	@Override
	public Boolean create(User obj) {
		if(checkUserAlreadyExist(obj.getMail())){
			Session session = HibernateUtil.openSession();
			Transaction tr = null;
			try{
				tr = session.beginTransaction();
				session.save(obj);
				//session.flush();
				tr.commit();
				return true;
			}catch (Exception e) {
				tr.rollback();
				e.printStackTrace();
			} finally {
				session.close();
			}
		}
		return false;
	}

	@Override
	public Boolean update(User obj) {
		if(!checkUserAlreadyExist(obj.getMail())){
			Session session = HibernateUtil.openSession();
			Transaction tr = null;
			try{
				tr = session.beginTransaction();
				session.update(obj);
				session.flush();
				tr.commit();
				return true;
			}catch (Exception e) {
				tr.rollback();
				e.printStackTrace();
			} finally {
				session.close();
			}
		}
		return false;
	}


	//TODO : v�rifier le comportement des delete on cascade (utile pour la gestion d'amis et les paris (� voir pour les defis)
	@Override
	public Boolean delete(User obj) {
		if(!checkUserAlreadyExist(obj.getMail())){
			Session session = HibernateUtil.openSession();
			Transaction tr = null;
			try{
				tr = session.beginTransaction();
				session.delete(obj);
				session.flush();
				tr.commit();
				return true;
			}catch (Exception e) {
				tr.rollback();
				e.printStackTrace();
			} finally {
				session.close();
			}
		}
		return false;

	}
	
	public User findWithId(int id) {
		//TODO
		return null;
	}

	public Boolean checkUserAlreadyExist(String mail){
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		Boolean rep = false;
		try{
			tr = session.beginTransaction();
			criteria.add(Restrictions.eq("mail", mail));
			List<User> users = criteria.list();
			rep = users.isEmpty();
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return rep;
	}

	public User login(String mail, String password) {
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		List<User> rep = null;
		try {
			tr = session.beginTransaction();
			criteria.add(Restrictions.eq("mail", mail));
			criteria.add(Restrictions.eq("password", password));
			rep = criteria.list();
			tr.commit();
		} catch(Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		if(rep.size() != 0)
			return rep.get(0);
		return null;
	}
	
	public User refresh(User user){
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		List<User> rep = null;
		try {
			tr = session.beginTransaction();
			criteria.add(Restrictions.eq("mail", user.getMail()));
			/*Hibernate.initialize(user.getParis());
			Hibernate.initialize(user.getDefis());
			Hibernate.initialize(user.getFriends());*/
			rep = criteria.list();
			tr.commit();
		} catch(Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		if(rep.size() != 0)
			return rep.get(0);
		return null;
	}

	public User subscribe(String mail, String pseudo, String password) {
		User user = new User(mail, pseudo, password);
		if(create(user))
			return findOne(mail);
		return null;
	}

	public User findOne(String mail) {
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		List<User> rep = null;
		try{
			tr = session.beginTransaction();
			criteria.add(Restrictions.eq("mail", mail));
			/*Hibernate.initialize(user.getParis());
			Hibernate.initialize(user.getDefis());
			Hibernate.initialize(user.getFriends());*/
			rep = criteria.list();
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}

		System.out.println("taille de rep " + rep.size());
		if(rep.size() != 0){
			System.out.println("yen a un");
			return rep.get(0);
		}
		return null;
	}

	public Boolean addBetToUser(Pari pari, String mail){
		User user = findOne(mail);
		if(user == null){
			return false;
		}
		if(user.getPoints() - pari.getMontant() >= 0){
			Session session = HibernateUtil.openSession();
			Transaction tr = null;
			try{
				tr = session.beginTransaction();
				
				/*Hibernate.initialize(user.getParis());*/
				
				pari.setUser(user);
				user.addPari(pari);
				user.setNbParisTotal(user.getNbParisTotal() + 1);
				user.setPoints(user.getPoints() - pari.getMontant());
				session.update(user);
				tr.commit();
				return true;
			}catch (Exception e) {
				tr.rollback();
				e.printStackTrace();
			} finally {
				session.close();
			}
			return false;
		}else{
			return false;
		}
	}


	public Boolean delBetToUser(Pari pari, String mail){
		User user = findOne(mail);
		if(user == null){
			return false;
		}
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		try{
			tr = session.beginTransaction();
			// ajout dans les pariHistorique avant de supprimer le pari
			PariHistorique pariHisto = new PariHistorique(pari, user.getId_user(), pari.getId_train().getStationDUA(),
					pari.getId_train().getNum_TheoricalTrainData());

			session.save(pariHisto);
			// supression du pari chez le user mais avant je check si je le credite ou pas d'un montant
			if(pari.getEtatPari() == 1){
				user.setNbParisJustes(user.getNbParisJustes() +1);
				user.setScore(user.getScore() + pari.getGainPossible());
				user.setPoints(user.getPoints() + pari.getGainPossible());

			}
			user.dellPari(pari);
			session.update(user);

			tr.commit();
			return true;
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return false;
	}

	public List<User> getTopTenScore(){
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		criteria.addOrder(Order.desc("score"));
		criteria.setMaxResults(10);
		List<User> rep = null;
		try{
			tr = session.beginTransaction();
			rep = criteria.list();
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return rep;

	}

	public List<User> getTopTenRatio(){
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(User.class);
		criteria.addOrder(Order.desc("ratio"));
		criteria.setMaxResults(10);
		List<User> rep = null;
		try{
			tr = session.beginTransaction();
			rep = criteria.list();
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return rep;
	}

	//valide les pari et supprime le train theorical
	public boolean validBetOnTheorical(TheoricalTrainData train){
		Session session = HibernateUtil.openSession();
		Transaction tr = null;
		Criteria criteria = session.createCriteria(Pari.class);
		criteria.add(Restrictions.eq("id_train", train));
		List<Pari> rep = null;
		try{
			tr = session.beginTransaction();
			rep = criteria.list();
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		if(rep.size() != 0){
			for(int i = 0 ; i < rep.size() ; i++){
				delBetToUser(rep.get(i), rep.get(i).getUser().getMail());
			}
		}
		Session session2 = HibernateUtil.openSession();
		Transaction tr2 = null;
		try{
			tr2 = session2.beginTransaction();
			session2.delete(train);
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return true;
	}
	
	public List<User> getFriends(String mail){
		User user = findOne(mail);
		List<User> rep = new ArrayList<User>();
		for(int i = 0; i < user.friendship.size(); i++){
			if(user.friendship.get(i).getOwner().equals(user)){
				rep.add(user.friendship.get(i).getTarget());
			}else{
				rep.add(user.friendship.get(i).getOwner());
			}
		}
		return null;
	}
	
	public Boolean newFriend(String mail_owner, String mail_target){
		
		User target = findOne(mail_target);
		
		Session session = HibernateUtil.openSession();
		Transaction tr = null;;
		try{
			tr = session.beginTransaction();
			User owner = findOne(mail_owner);
			/*Hibernate.initialize(owner.getFriends());*/
			owner.addFriend(new Friendship(owner, target, 0));
			session.update(owner);
			tr.commit();
		}catch (Exception e) {
			tr.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return true;
	}
}
